package com.coderworm.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.ReadTimeoutHandler;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Netty版RTCM服务端：异步非阻塞IO，高并发支撑
 */
public class RtcmNettyServer {
    // 基础配置（与原逻辑一致）
    private static final int TCP_PORT = 8888;
    private static final String RTCM_SAVE_DIR = "D:/rtcm_files/";
    private static final String SALT = "RtcmSecure2025_#";
    // 安全配置（IP白名单、授权用户，与原逻辑一致）
    private static final Set<String> ALLOWED_IPS = new HashSet<>();
    private static final Set<String> AUTH_USERS = new HashSet<>();

    static {
        // 初始化IP白名单与授权用户（与原逻辑一致）
        ALLOWED_IPS.add("127.0.0.1");
        ALLOWED_IPS.add("192.168.1.100");
        AUTH_USERS.add("rtcm_device_001:b39c8fa70ebd421d39ed55d49c6d6d075ecfa075f0d00f2b2f687142d73aeff5");
    }

    public void start() throws InterruptedException {
        // 1. 定义Netty核心线程组：BossGroup（处理连接请求）+ WorkerGroup（处理IO事件）
        // 核心优化：线程数固定为CPU核心数×2，无需随并发增长（传统IO需动态扩线程）
        EventLoopGroup bossGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors());
        EventLoopGroup workerGroup = new NioEventLoopGroup(Runtime.getRuntime().availableProcessors() * 2);

        try {
            // 2. 服务端启动器配置
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) // 异步非阻塞ServerChannel
                    .option(ChannelOption.SO_BACKLOG, 1024) // 连接队列大小（优化TCP握手队列）
                    .childOption(ChannelOption.SO_KEEPALIVE, true) // 开启TCP保活，避免僵尸连接
                    .childOption(ChannelOption.TCP_NODELAY, true) // 禁用Nagle算法，小数据传输更及时
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            // 3. 配置ChannelPipeline（责任链模式，处理IO事件）
                            ChannelPipeline pipeline = ch.pipeline();
                            // 3.1 超时处理器：30秒无数据读取则关闭连接（避免永久阻塞，替代原Socket.setSoTimeout）
                            pipeline.addLast(new ReadTimeoutHandler(30, TimeUnit.SECONDS));
                            // 3.2 自定义处理器：身份验证（用户名密码密文校验）
                            pipeline.addLast(new RtcmAuthHandler(ALLOWED_IPS, AUTH_USERS, SALT));
                            // 3.3 自定义处理器：RTCM文件接收（帧头校验、文件写入、CRC校验）
                            pipeline.addLast(new RtcmFileHandler(RTCM_SAVE_DIR));
                        }
                    });

            // 4. 绑定端口，启动服务端（异步绑定，sync()等待完成）
            ChannelFuture future = bootstrap.bind(TCP_PORT).sync();
            System.out.println("Netty RTCM服务端启动成功，监听端口：" + TCP_PORT);
            System.out.println("IO线程数：Boss=" + bossGroup.next().toString() + "，Worker=" +  bossGroup.next().toString() );

            // 5. 等待服务端关闭（阻塞，直到调用channel.close()）
            future.channel().closeFuture().sync();
        } finally {
            // 6. 优雅关闭线程组（释放资源）
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            System.out.println("Netty RTCM服务端已关闭");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        new RtcmNettyServer().start();
    }
}